package com.ee.bruscar.generator.model;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class TemplateMethod
{
	private Method method;
	
	public TemplateMethod( Method method )
	{
		this.method = method;
	}
	
	public String getName() 
	{
		return method.getName();
	}
	
	public String getFieldName()
	{
		String stripped = method.getName().substring(3, method.getName().length() );
		String firstLetter = stripped.substring(0,1);
		String remainder = stripped.substring(1, stripped.length() );
		
		return firstLetter.toLowerCase() + remainder;
	}
	
	public boolean isBoolean()
	{
		Class innerSetterType = getSetterType().getInnerClass();
		return innerSetterType.equals( Boolean.TYPE );
	}
	
	public boolean isPrimitive()
	{
		Class innerSetterType = getSetterType().getInnerClass();
		
		if( innerSetterType.equals( Boolean.TYPE ) )
		{
			return true;
		}
		if( innerSetterType.equals( Double.TYPE ) )
		{
			return true;
		}
		if( innerSetterType.equals( Integer.TYPE ) )
		{
			return true;
		}
		if( innerSetterType.equals( Long.TYPE ) )
		{
			return true;
		}
		return false;
	}
	
	public String getPrimitiveName() 
	{
		Class innerSetterType = getSetterType().getInnerClass();
		
		if( innerSetterType.equals( Boolean.TYPE ) )
		{
			return "Boolean";
		}
		if( innerSetterType.equals( Double.TYPE ) )
		{
			return "Double";
		}
		if( innerSetterType.equals( Integer.TYPE ) )
		{
			return "Int";
		}
		if( innerSetterType.equals( Long.TYPE ) )
		{
			return "Long";
		}
		
		throw new RuntimeException( innerSetterType.getName() + " is not a primitive.");
	}
	
	public boolean isSetterList()
	{
		Class[] interfaces = getSetter().getInterfaces();
		for( int i = 0 ; i < interfaces.length ; i++ )
		{
			if( interfaces[i].equals(List.class))
			{
				return true;
			}
			
			if( interfaces[i].equals(Collection.class))
			{
				return true;
			}
		}
		return false;
	}
	
	public Class getBoxedPrimitive()
	{
		if( isBoolean() )
		{
			return Boolean.class;
		}
		return null;
	}
	
	public boolean isReturnTypeList()
	{
		Class[] returnTypeInterfaces = method.getReturnType().getInterfaces() ;
		
		if( method.getReturnType().equals(List.class))
		{
			return true;
		}
		return false;
	}
	
	public TemplateClass getListReturnType() 
	{
		if( !method.getReturnType().equals(List.class) )
		{
			throw new RuntimeException("can't return a list return for method: " + method.getName() );
		}
		
		Type returnType = method.getGenericReturnType();
		
		if(returnType instanceof ParameterizedType)
		{
		    ParameterizedType type = (ParameterizedType) returnType;
		    Type[] typeArguments = type.getActualTypeArguments();
		    Class typeArgClass = (Class) typeArguments[0];
		    return new TemplateClass( typeArgClass );
		}
		
		return null;

	}
	
	public TemplateClass getSetterListType()
	{
		Type[] types = method.getGenericParameterTypes(); 
		Type argType = types[0];
		if( argType instanceof ParameterizedType )
		{
			  ParameterizedType type = (ParameterizedType) argType;
			  Type[] typeArguments = type.getActualTypeArguments();
			  Class typeArgClass = (Class) typeArguments[0];
			  return new TemplateClass( typeArgClass );
		}
		return null;
	}
	
	public TemplateClass getReturnType()
	{
		return new TemplateClass( method.getReturnType() );
	}
	
	public Class[] getParameterTypes()
	{
		return this.method.getParameterTypes();
	}
	
	public boolean isCustom()
	{
		Class[] setterTypes = method.getParameterTypes();
		
		if( setterTypes.length != 1 )
		{
			throw new RuntimeException( "only setters supported");
		}
		
		TemplateClass templateClass = new TemplateClass( setterTypes[0] );
		return templateClass.isCustomType();
	}
	
	public boolean isStringReturned()
	{
		return method.getReturnType().equals( String.class );
	}
	
	public TemplateClass getSetterType()
	{
		return new TemplateClass( getSetter() );
	}
	
	public String getSetterTypeSimpleName()
	{
		return getSetter().getSimpleName();
	}
	
	private Class getSetter()
	{
		Class[] setterTypes = method.getParameterTypes();
		
		if( setterTypes.length != 1 )
		{
			throw new RuntimeException( "only setters supported");
		}
		return setterTypes[0];
	
	}
}
